package app

import (
    "net/http"
    "path"
    "fmt"
)

const (
    ErrNotFound = "page not found"
)

type (
    // Router 实现了 http.Handler。保存所有的路由
    Router struct {
        // 保存所有的 handlerFunc
        globalHandlers HandlersChain
        // 路由根路径
        basePath string
        // 保存所有的路由
        trees methodTrees
    }

    HandlersChain []HandlerFunc
    // 处理器
    HandlerFunc func(*Context)
)

// 初始化
func New() *Router  {
    return &Router{
        basePath: "/",
    }
}

// 注册方法
func (r *Router) Use (handlers ...HandlerFunc)  {
    r.globalHandlers = append(r.globalHandlers, handlers...)
}

// 注册分组路由
func (r *Router) Group (partPath string, fn func(), handlers ...HandlerFunc) {
    rootBasePath := r.basePath
    rootHandlers := r.globalHandlers
    r.basePath = path.Join(r.basePath, partPath)
    r.globalHandlers = r.combineHandlers(handlers)
    fn()
    r.basePath = rootBasePath
    r.globalHandlers = rootHandlers
}

// 注册 GET 路由
func (r *Router) GET(partPath string, handlers ...HandlerFunc)  {
    routePath := path.Join(r.basePath, partPath)
    handlers = r.combineHandlers(handlers)
    r.addRoute(http.MethodGet, routePath, handlers)
}

// 注册 POST 路由
func (r *Router) POST(partPath string, handlers ...HandlerFunc)  {
    routePath := path.Join(r.basePath, partPath)
    handlers = r.combineHandlers(handlers)
    r.addRoute(http.MethodPost, routePath, handlers)
}

// 注册 PUT 路由
func (r *Router) PUT(partPath string, handlers ...HandlerFunc)  {
    routePath := path.Join(r.basePath, partPath)
    handlers = r.combineHandlers(handlers)
    r.addRoute(http.MethodPut, routePath, handlers)
}

// 注册 DELETE 路由
func (r *Router) DELETE(partPath string, handlers ...HandlerFunc)  {
    routePath := path.Join(r.basePath, partPath)
    handlers = r.combineHandlers(handlers)
    r.addRoute(http.MethodDelete, routePath, handlers)
}

// 注册 PATCH 路由
func (r *Router) PATCH(partPath string, handlers ...HandlerFunc)  {
    routePath := path.Join(r.basePath, partPath)
    handlers = r.combineHandlers(handlers)
    r.addRoute(http.MethodPatch, routePath, handlers)
}

// 合并处理器方法
func (r *Router) combineHandlers(handlers HandlersChain) HandlersChain  {
    finallyLen := len(r.globalHandlers) + len(handlers)
    finallyHandlers := make([]HandlerFunc, finallyLen)
    copy(finallyHandlers, r.globalHandlers)
    copy(finallyHandlers[len(r.globalHandlers):], handlers)
    return  finallyHandlers
}

// 添加路由
func (r *Router) addRoute(method string, path string, handlers HandlersChain)  {
    root := r.trees.get(method)
    if root == nil {
        root = new(node)
        r.trees = append(r.trees, methodTree{method: method, root: root})
    }
    root.addRoute(path, handlers)
}

// 实现 http.ServeHTTP
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)  {
    httpMethod := req.Method

    if httpMethod == http.MethodOptions {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Headers", "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since,Token")
        w.WriteHeader(http.StatusNoContent)
        return
    }
    c := &Context{
        Request: req,
        Writer: w,
        handlers: nil,
        index: -1,
    }
    routePath := req.URL.Path
    // 匹配路由
    t := r.trees
    for i, tl := 0, len(t); i < tl; i++ {
        if t[i].method == httpMethod {
            root := t[i].root
            handlers, params, _ := root.getValue(routePath, c.Params, false)
            if handlers != nil {
                c.handlers = handlers
                c.Params = params
                c.Next()
                return
            }
            break
        }
    }
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since,Token")
    w.WriteHeader(http.StatusNotFound)
    fmt.Fprintf(w, ErrNotFound)
    return
}